package com.doubao.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.doubao.auth.client.WechatClient;
import com.doubao.auth.config.JwtConfig;
import com.doubao.auth.dto.JwtAuthResponse;
import com.doubao.auth.dto.WxLoginRequest;
import com.doubao.auth.entity.AuthUser;
import com.doubao.auth.mapper.AuthUserMapper;
import com.doubao.auth.service.WxAuthService;
import com.doubao.auth.util.JwtUtils;
import com.doubao.common.result.Result;
import com.doubao.common.utils.RedisTemplateFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 微信认证服务实现
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class WxAuthServiceImpl implements WxAuthService {

    private final WechatClient wechatClient;
    private final AuthUserMapper authUserMapper;
    private final JwtUtils jwtUtils;
    private final PasswordEncoder passwordEncoder;
    private RedisTemplate<String, String> redisTemplate;
    private final JwtConfig jwtConfig;
    private final ObjectMapper objectMapper;

    @PostConstruct
    public void init() {
        this.redisTemplate = RedisTemplateFactory.getStringRedisTemplate();
        log.info("WxAuthServiceImpl使用RedisTemplateFactory获取StringRedisTemplate");
    }

    @Value("${wx.appId}")
    private String appId;

    private static final String REFRESH_TOKEN_KEY_PREFIX = "refresh:token:";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<JwtAuthResponse> wxLogin(WxLoginRequest request) {
        try {
            // 1. 通过微信服务获取微信用户信息
            Result<Map<String, Object>> wxUserInfoResult = wechatClient.miniappLogin(request);
            if (!wxUserInfoResult.isSuccess()) {
                return Result.failed(wxUserInfoResult.getMessage());
            }

            Map<String, Object> wxUserInfo = wxUserInfoResult.getData();
            String openid = (String) wxUserInfo.get("openid");
            String unionid = (String) wxUserInfo.getOrDefault("unionid", "");

            if (StringUtils.isBlank(openid)) {
                return Result.failed("获取微信用户信息失败");
            }

            // 2. 查找是否已存在关联的用户 - 修改为传递完整的wxUserInfo
            AuthUser user = findUserByWechatInfo(openid, unionid, wxUserInfo);

            // 3. 如果用户不存在，创建新用户
            if (user == null) {
                user = createUserFromWechatInfo(wxUserInfo);
            }

            // 4. 生成JWT令牌 - 修改为使用包含userId的方法
            String token = jwtUtils.generateToken(user.getUsername(), user.getId());
            String refreshToken = jwtUtils.generateRefreshToken(user.getUsername());

            // 5. 将刷新令牌存入Redis
            redisTemplate.opsForValue().set(
                    REFRESH_TOKEN_KEY_PREFIX + user.getUsername(),
                    refreshToken,
                    jwtConfig.getRefreshExpiration(),
                    TimeUnit.DAYS
            );

            // 6. 更新用户最后登录信息
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(""); // 可以从请求中获取IP
            user.setLoginCount(user.getLoginCount() + 1);
            authUserMapper.updateById(user);

            // 7. 构建响应对象
            JwtAuthResponse authResponse = new JwtAuthResponse();
            authResponse.setToken(token);
            authResponse.setRefreshToken(refreshToken);
            authResponse.setUserId(user.getId());
            authResponse.setUsername(user.getUsername());
            authResponse.setNickname(user.getNickname());
            authResponse.setAvatar(user.getAvatar());
            authResponse.setVipStatus(user.getVipStatus());

            return Result.success(authResponse);
        } catch (Exception e) {
            log.error("微信登录失败", e);
            return Result.failed("微信登录失败: " + e.getMessage());
        }
    }

    /**
     * 根据微信信息查找用户
     */
    private AuthUser findUserByWechatInfo(String openid, String unionid, Map<String, Object> wxUserInfo) {
        // 1. 先尝试通过手机号查找用户（这是新增的逻辑）
        Object rawDataObj = wxUserInfo.get("rawData");
        if (rawDataObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> rawData = (Map<String, Object>) rawDataObj;
            String phoneNumber = (String) rawData.get("purePhoneNumber");

            if (StringUtils.isNotBlank(phoneNumber)) {
                log.info("尝试通过手机号 {} 查找已有用户", phoneNumber);
                LambdaQueryWrapper<AuthUser> phoneWrapper = new LambdaQueryWrapper<>();
                phoneWrapper.eq(AuthUser::getPhone, phoneNumber);
                AuthUser userByPhone = authUserMapper.selectOne(phoneWrapper);

                if (userByPhone != null) {
                    log.info("通过手机号 {} 找到已有用户 ID: {}", phoneNumber, userByPhone.getId());
                    // 更新用户的微信关联信息
                    userByPhone.setUnionid(unionid);
                    userByPhone.setMiniappOpenid(openid);
                    authUserMapper.updateById(userByPhone);
                    return userByPhone;
                }
            }
        }

        // 2. 然后尝试通过unionid查找
        if (StringUtils.isNotBlank(unionid)) {
            LambdaQueryWrapper<AuthUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AuthUser::getUnionid, unionid);
            AuthUser userByUnionid = authUserMapper.selectOne(wrapper);
            if (userByUnionid != null) {
                return userByUnionid;
            }
        }

        // 3. 最后尝试通过openid查找
        if (StringUtils.isNotBlank(openid)) {
            LambdaQueryWrapper<AuthUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AuthUser::getMiniappOpenid, openid);
            return authUserMapper.selectOne(wrapper);
        }

        return null;
    }

    private AuthUser createUserFromWechatInfo(Map<String, Object> wxUserInfo) {
        AuthUser user = new AuthUser();
        user.setUuid(UUID.randomUUID().toString().replace("-", ""));

        // 使用微信openid生成唯一用户名
        String openid = (String) wxUserInfo.get("openid");
        String username = "wx_" + openid.substring(openid.length() - 8);

        // 确保用户名唯一
        LambdaQueryWrapper<AuthUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AuthUser::getUsername, username);
        if (authUserMapper.selectCount(wrapper) > 0) {
            username = "wx_" + System.currentTimeMillis();
        }

        user.setUsername(username);

        // 设置随机密码
        String randomPassword = UUID.randomUUID().toString().substring(0, 16);
        user.setPassword(passwordEncoder.encode(randomPassword));

        // 设置用户信息
        user.setNickname((String) wxUserInfo.getOrDefault("nickName", username));
        user.setAvatar((String) wxUserInfo.getOrDefault("avatarUrl", ""));
        user.setUnionid((String) wxUserInfo.getOrDefault("unionid", ""));
        user.setMiniappOpenid(openid);

        // 新增：从rawData中获取手机号
        Object rawDataObj = wxUserInfo.get("rawData");
        if (rawDataObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> rawData = (Map<String, Object>) rawDataObj;
            String phoneNumber = (String) rawData.get("purePhoneNumber");
            if (StringUtils.isNotBlank(phoneNumber)) {
                user.setPhone(phoneNumber);
                log.info("为新用户设置手机号: {}", phoneNumber);
            }
        }

        // 设置默认值
        user.setStatus(1); // 正常状态
        user.setDeleted(0); // 未删除
        user.setVipStatus(0); // 非VIP
        user.setLoginCount(1); // 首次登录
        user.setTotalTokensBalance(99999999); // 初始余额设为0，由token服务统一初始化
        user.setTotalTokensUsed(0L);
        user.setRegisterSource("miniapp");
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());

        authUserMapper.insert(user);

        return user;
    }
}